package edu.washington.cs.sounddetector.server.servlet;

import java.io.IOException;
import java.io.InputStreamReader;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.JsonParseException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import edu.washington.cs.sounddetector.server.api.Method;
import edu.washington.cs.sounddetector.server.api.MethodConverter;
import edu.washington.cs.sounddetector.server.api.MethodLogic;
import edu.washington.cs.sounddetector.server.api.MethodResult;
import edu.washington.cs.sounddetector.server.api.exception.SoundDetectorInternalErrorException;

/**
 * Main entry point of all api calls.
 * 
 * @author the.dylan.price@gmail.com
 * 
 */
public class SoundDetectorAPIServlet extends HttpServlet
{
    /**
     * Serial number for serialization.
     */
    private static final long serialVersionUID = -7810505933356321858L;

    private static final Log log = LogFactory.getLog(SoundDetectorAPIServlet.class);

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
    {
        executeMethodAndReturnResponse(req, resp);
    }

    private void executeMethodAndReturnResponse(HttpServletRequest req, HttpServletResponse resp)
            throws IOException
    {
        try
        {
            WebApplicationContext context = WebApplicationContextUtils
                    .getRequiredWebApplicationContext(getServletContext());

            String methodName = req.getPathInfo().substring(1);

            Class<? extends Method> methodClass = MethodConverter.getInstance().getMethodClass(
                    methodName);

            if (methodClass == null)
            {
                resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                resp.getWriter().println("No method by the name of: " + methodName);
            }
            else
            {
                InputStreamReader reader = new InputStreamReader(req.getInputStream());
                Method method = MethodConverter.getInstance()
                        .deserializeMethod(reader, methodClass);

                MethodLogic methodLogic = (MethodLogic) context.getBean("methodLogic");
                MethodResult<?> result = methodLogic.execute(method);

                resp.setStatus(HttpServletResponse.SC_OK);
                resp.getWriter().println(MethodConverter.getInstance().serializeResult(result));
            }
        }
        catch (JsonParseException e)
        {
            log.info("JSONParseException", e);
            resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            resp.getWriter().println("Malformed json syntax: " + e.getMessage());
        }
        catch (SoundDetectorInternalErrorException e)
        {
            log.error("Internal error!", e);
            e.printStackTrace(System.out);
            resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            resp.getWriter().println("Internal Server Error: " + e.getMessage());
        }
        catch (Exception e)
        {
            log.error("Unexpected exception!", e);
            e.printStackTrace(System.out);
            resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            resp.getWriter()
                    .println(
                            "Server snafu! The server may be in an inconsistent state, let the administrator know as soon as possible. Message: "
                                    + e.getMessage());
        }
        resp.flushBuffer();
    }
}
